#ifndef _FSBLOCK_H
#define	_FSBLOCK_H
/*
 * FSBlock.h
 *
 * Created on February 4, 2005, 8:36 AM
 * Modified:
 *      CGP; 1/25/09; Converted to C++
 */

#include "BlockException.h"
#include "Disk.h"

/** A representation of a Block of data on disk, including a disk address (block number) for the block.
 * Every Block
 * represents a fixed size buffer (e.g., 512 bytes) of RAM data called the "m_buffer".
 * Blocks typically contain some int values (4 byte integer) values in
 * some of their m_buffer locations.
 * E.g., a block can contain
 * a block number-- an address (of the next block
 * on Disk in a linked organization of disk blocks) called the "next pointer".
 * The methods SetInt and GetInt are used to maintain these values.
 *
 * Note: In this class we sometimes call a disk address a "pointer" even though these "pointers" are not
 * references to RAM memory, but references to locations (blocks) on disk.
 *
 * @author chris
 */
class FSBlock { // File System Block
private:
    void ConstructorInit(int length, int blockNumber);
    bool GetDebug();

public:
    static void Debug(bool state);

    /** Creates a RAM representation of a block of data. Doesn't do any error checking. Allocates a new RAM byte array m_buffer, and initializes
     * the buffer of data (data member, m_buffer) to zeros.
     * Does not alter the disk.
     *
     * @param blockNumber should range betwen 0 and (1 less than the number of blocks on the Disk).
	 * This is used to set a data member for the Block.
     *
     * @param length should be the same as the block size on the Disk. Allocates the m_buffer with this length.
     * 
     */
    FSBlock(int blockNumber, int length);

	/** Deallocates the m_buffer for the Block.
	 */
    ~FSBlock();

    /** Creates a Block object in RAM. Initializes the m_buffer of data to zeros.
     * The block number data member is set to 0. Does not alter the disk.
     *
     * @param length is the number of bytes to allocate for the m_buffer.
     */
    FSBlock(int length);

    /** Set all bytes of the m_buffer of this Block to 0.
     * Does not alter the disk.
     */
    void ClearBuffer();

    /**
     * Returns the block number for this FSBlock, returns value of a data member.
	 * Does not access Disk.
     */
    unsigned int GetBlockNumber();

    /**
     * Changes the block number data member for this FSBlock RAM object. Doesn't write the change to disk.
     * The block number is not represented by the m_buffer, but rather it 
     * is represented as a data member of the FSBlock.
     * The block number is
     * the location where you just read the block from on Disk, or the location where you intend
     * to write the FSBlock to disk.
     */
    void SetBlockNumber(unsigned int number);

    /** Attempts to read a FSBlock from a Disk. If the block as written to Disk had
     * int value(s) (e.g., established by SetInt()), those int value(s) will be available after use of this
	 * constructor by calling GetInt().
     *
     * @param blockNumber The block number of the FSBlock to read. This
     * can range between 0 and numberOfBlocks()-1 (inclusive) for this Disk object.
     *
     * @param disk is the Disk to read from.
     *
     * @throws BlockException when the blockNumber is invalid, when there is an I/O error,
     *      or when the m_buffer is NULL.
     */
    FSBlock(unsigned int blockNumber, Disk *disk);

    /** Writes the data (m_buffer) from the FSBlock to its block number on the Disk. The FSBlock must
     * have the correct information. E.g., this can be the case because a previous Block constructor
     * reading from a Disk returned the FSBlock.
     *
     * @param disk The Disk to write this FSBlock to.
	 * @return true iff the call succeeded in writing the FSBlock to the Disk.
     */
    bool Write(Disk *disk);

    /** Obtain a reference to the m_buffer data member for this FSBlock.
     * @return a reference to (not a copy of) the byte buffer for this Block.
     */
    unsigned char *GetBuffer();

    /** Changes the reference of the m_buffer. No copy is made!
     * Memory for the original m_buffer is first deallocated by this method (using "delete").
     * @param buffer is used by reference-- a copy is not made. Do not deallocate the buffer passed to this call
	 *		after the call.
     */
    void SetBuffer(unsigned char *buffer);

    /** Enables the caller to treat the first bytes of the m_buffer as an array of int's.
     * Changes one of these int's in the m_buffer.
     * If arrayIndex=0, the first 4 bytes of the m_buffer are changed to 
     *      the binary value in the intValue parameter ("first integer").
     * If arrayIndex=1, the second 4 bytes are changed, etc. ("second integer").
	 * Etc.
     * The integers are stored in network byte order (a.k.a., big endian byte order).
     *
     * @param intValue gives the integer
     * @param arrayIndex gives the location (in terms of 4 byte ints) in the m_buffer to change
     */
    void SetInt(int intValue, int arrayIndex);

    /** Retrieves one of the int's in the m_buffer as set by SetInt
     * @param arrayIndex gives the relative 4 byte location to access. See SetInt.
     */
    int GetInt(int arrayIndex);
	
    /** Return the number of bytes in the buffer for this block. This
     * is the block size of this block.
     */
    unsigned int GetBlockSize();

	/** Print out the contents of the FSBlock. Prints the m_buffer bytes in hex and decimal representation.
	 * Prints out the values of the other data members. For debugging.
	 */
	 void Print();

private:
    unsigned int m_blockNumber; // the number of this block as either read from disk using the Block constructor
	// or as intended to be written to disk using FSBlock::Write
	
    unsigned char *m_buffer; // data from the disk block, or to be written to the disk block
    unsigned int m_length; // length of m_buffer
    static bool m_BlockDebugFlag; // Is debug output on?
};



#endif // _FSBLOCK_H


